﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using BusinessObjects;
using System.Collections.Generic;
using YourWorld.Common.Infrastucture.Events;
using MainGameModule.ViewModels;
using System.Windows.Data;
using System.Diagnostics;

namespace MainGameModule.Views
{
    public class MainPanel : Canvas
    {
        private Random random = new Random();
        private bool initialized = false;
        private bool isProcessingRequests = false;

        private double currentScale = 1;
        private int sleep = Consts.SleepBetweenPlayerMoves;
        private DateTime lastMoveTime = DateTime.Now;

        private List<Player> allPlayers;
        private Quest payload = null;

        public MainPanel()
        {
            base.LayoutUpdated += new EventHandler( this.MainPanel_LayoutUpdated );

            GameTaskManager.Instance.PendingTasksAvailable += delegate
            {
                if ( this.isProcessingRequests == false )
                {
                    this.isProcessingRequests = true;
                    this.ProcessNextTask();
                }
            };

            this.Width = Consts.MapWidth;
            this.Height = Consts.MapHeight;

            this.allPlayers = new List<Player>();

            this.MouseWheel += new MouseWheelEventHandler( MainPanel_MouseWheel );
            this.KeyDown += new KeyEventHandler( MainPanel_KeyDown );

            EventService.Aggregator.GetEvent<ScaleGameMapEvent>().Subscribe( this.ChangeScale );
            EventService.Aggregator.GetEvent<UpdateLayoutEvent>().Subscribe( this.RefreshLayout );
            EventService.Aggregator.GetEvent<BuildQuestEvent>().Subscribe( this.SavePayload );

            this.MouseRightButtonDown += new MouseButtonEventHandler( MainPanel_MouseRightButtonDown );
        }

        public void SavePayload( Quest payload )
        {
            this.payload = payload;
        }

        private void MainPanel_MouseRightButtonDown( object sender, MouseButtonEventArgs e )
        {
            if ( this.payload == null )
                return;

            e.Handled = true;
            Point p = e.GetPosition( this );

            this.payload.X = p.X;
            this.payload.Y = p.Y;

            EventService.Aggregator.GetEvent<BuildQuestEvent>().Publish( this.payload );
            this.payload = null;
        }

        void MainPanel_MouseRightButtonUp( object sender, MouseButtonEventArgs e )
        {
            MessageBox.Show( "HI" );
        }

        private void MainPanel_KeyDown( object sender, KeyEventArgs e )
        {
            e.Handled = true;
        }

        private void MainPanel_MouseWheel( object sender, MouseWheelEventArgs e )
        {

            if ( e.Delta > 0 )
                this.currentScale += 0.05;
            else if ( this.currentScale > 0 )
                this.currentScale -= 0.05;

            if ( this.currentScale <= 1 && this.currentScale >= Consts.MapMinScale )
            {
                EventService.Aggregator.GetEvent<ScaleGameMapEvent>().Publish( this.currentScale );
            }
        }

        public void RefreshLayout( bool param )
        {
            this.InitializeContentPresenters();
        }

        public void ChangeScale( double scale )
        {
            ScaleTransform s = this.RenderTransform as ScaleTransform;
            s.CenterX = 0.5;
            s.CenterY = 0;

            s.ScaleX = scale;
            s.ScaleY = scale;
        }

        private void ProcessNextTask()
        {
            this.initialized = true;
            SimpleTask task = GameTaskManager.Instance.GetPendingTask();

            if ( task != null )
            {
                Storyboard storyboard = this.MovePlayerTask( task );

                if ( storyboard == null )
                {
                    this.UpdateLayout();
                    return;
                }
                this.PerformTask( task, storyboard );
            }
            else
            {
                this.isProcessingRequests = false;
            }
        }

        private Storyboard MovePlayerTask( SimpleTask task )
        {
            Player mainPlayer = task.GameObject as Player;
            Debug.Assert( mainPlayer != null );

            if ( mainPlayer.ContentItemn == null )
                this.InitializeContentPresenters();

            Debug.Assert( mainPlayer.ContentItemn != null );
            Storyboard movePlayer = new Storyboard();

            DoubleAnimation moveLeft = new DoubleAnimation()
            {
                From = task.CurrentLocation.X,
                To = task.NewLocation.X,
                Duration = new Duration( TimeSpan.FromMilliseconds( task.Duration ) )
            };

            PropertyPath targetPropertyLeft = new PropertyPath( Canvas.LeftProperty );
            Storyboard.SetTargetProperty( moveLeft, targetPropertyLeft );
            Storyboard.SetTarget( moveLeft, mainPlayer.ContentItemn );

            DoubleAnimation moveRight = new DoubleAnimation()
            {
                From = task.CurrentLocation.Y,
                To = task.NewLocation.Y,
                Duration = new Duration( TimeSpan.FromMilliseconds( task.Duration ) )
            };
            PropertyPath targetPropertyTop = new PropertyPath( Canvas.TopProperty );
            Storyboard.SetTargetProperty( moveRight, targetPropertyTop );
            Storyboard.SetTarget( moveRight, mainPlayer.ContentItemn );

            movePlayer.Children.Add( moveLeft );
            movePlayer.Children.Add( moveRight );

            return movePlayer;
        }

        private void InitializeContentPresenters()
        {
            foreach ( UIElement children in this.Children )
            {
                if ( children.Visibility == Visibility.Collapsed )
                    continue;

                GameObject tile = children.GetValue( DataContextProperty ) as GameObject;
                if ( tile == null )
                    continue;

                children.SetValue( Canvas.LeftProperty, tile.X );
                children.SetValue( Canvas.TopProperty, tile.Y );
                children.SetValue( Canvas.ZIndexProperty, tile.ZIndex );

                if ( tile is Player )
                {
                    Binding myBinding = new Binding( "ZIndex" );
                    myBinding.Source = tile;
                    ( children as FrameworkElement ).SetBinding( Canvas.ZIndexProperty, myBinding );

                    children.Visibility = System.Windows.Visibility.Visible;

                    Player player = tile as Player;
                    player.ContentItemn = children as ContentPresenter;
                }
            }
        }

        private void PerformTask( SimpleTask task, Storyboard storyboard )
        {
            storyboard.Completed += delegate
            {
                if ( task.Complete != null )
                    task.Complete();

                this.ProcessNextTask();
            };

            storyboard.Begin();
        }

        private void MainPanel_LayoutUpdated( object sender, EventArgs e )
        {
            if ( this.Children.Count == 0 || initialized )
                return;

            this.InitializeContentPresenters();
        }

        private void MainPanel_KeyUp( object sender, KeyEventArgs e )
        {
            MoveDirection? direction = null;
            switch ( e.Key )
            {
                case Key.Left: direction = MoveDirection.Left; break;
                case Key.Right: direction = MoveDirection.Right; break;
                case Key.Up: direction = MoveDirection.Up; break;
                case Key.Down: direction = MoveDirection.Down; break;
            }

            if ( direction != null )
                EventService.Aggregator.GetEvent<MovePlayerEvent>().Publish( ( MoveDirection )direction );
        }
    }

}
